#include <iostream>
#include <fstream>

#include "smartcar.hpp"

using namespace std;

void Tire::set(const string& tire_type, int tire_size) {
    type = tire_type;
    size = tire_size;
}
void Tire::print() const {
    cout << "Tire Type: " << type << ", Size: " << size << " inches" << endl;
}
void Tire::save(ofstream& file) const {
    if (file.is_open()) {
        file << "Tire Type: " << type << ", Size: " << size << " inches" << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void Chassis::set(const string& chassis_id, const string& chassis_model, int chassis_wheelbase, int chassis_track,
                  int ground_clearance, int turning_radius, const string& drive, int range) {
    model = chassis_model;
    wheelbase = chassis_wheelbase;
    track = chassis_track;
    min_ground_clearance = ground_clearance;
    min_turning_radius = turning_radius;
    drive_type = drive;
    max_range = range;
    for (int i = 0; i < 4; ++i) {
        Tire tire;
        tire.set();
        tires.push_back(tire);
    }
    id = chassis_id;
}
void Chassis::print() const {
    cout << "Chassis ID: " << id << endl;
    cout << "Model: " << model << endl;
    cout << "Wheelbase: " << wheelbase << " mm" << endl;
    cout << "Track: " << track << " mm" << endl;
    cout << "Min Ground Clearance: " << min_ground_clearance << " mm" << endl;
    cout << "Min Turning Radius: " << min_turning_radius << " mm" << endl;
    cout << "Drive Type: " << drive_type << endl;
    cout << "Max Range: " << max_range << " km" << endl;
    cout << "Tires:" << endl;
    for (const auto& tire : tires) {
        tire.print();
    }
}
void Chassis::save(ofstream& file) const {
    if (file.is_open()) {
        file << "Chassis ID: " << id << endl;
        file << "Model: " << model << endl;
        file << "Wheelbase: " << wheelbase << " mm" << endl;
        file << "Track: " << track << " mm" << endl;
        file << "Min Ground Clearance: " << min_ground_clearance << " mm" << endl;
        file << "Min Turning Radius: " << min_turning_radius << " mm" << endl;
        file << "Drive Type: " << drive_type << endl;
        file << "Max Range: " << max_range << " km" << endl;
        file << "Tires:" << endl;
        for (const auto& tire : tires) {
            tire.save(file);
        }
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}
string Chassis::get() const {
    return id;
}

void AGX::set(const string& agx_model, int agx_AI, int agx_GPU, int agx_tensor_cores,
              int agx_vmemory, int agx_storage) {
    model = agx_model;
    AI = agx_AI;
    GPU = agx_GPU;
    tensor_cores = agx_tensor_cores;
    vmemory = agx_vmemory;
    storage = agx_storage;
}
void AGX::print() const {
    cout << "AGX Model: " << model << endl;
    cout << "AI Cores: " << AI << endl;
    cout << "GPU Cores: " << GPU << endl;
    cout << "Tensor Cores: " << tensor_cores << endl;
    cout << "Video Memory: " << vmemory << " GB" << endl;
    cout << "Storage: " << storage << " GB" << endl;
}
void AGX::save(ofstream& file) const {
    if (file.is_open()) {
        file << "AGX Model: " << model << endl;
        file << "AI Cores: " << AI << endl;
        file << "GPU Cores: " << GPU << endl;
        file << "Tensor Cores: " << tensor_cores << endl;
        file << "Video Memory: " << vmemory << " GB" << endl;
        file << "Storage: " << storage << " GB" << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void DualCamera::set(const string& camera_model, const string& camera_camera, const string& camera_resolution,
                     int camera_fps, const string& camera_fov, int camera_depth_fps) {
    model = camera_model;
    camera = camera_camera;
    resolution = camera_resolution;
    fps = camera_fps;
    fov = camera_fov;
    depth_fps = camera_depth_fps;
}
void DualCamera::print() const {
    cout << "Dual Camera Model: " << model << endl;
    cout << "Camera: " << camera << endl;
    cout << "Resolution: " << resolution << endl;
    cout << "FPS: " << fps << endl;
    cout << "FOV: " << fov << endl;
    cout << "Depth FPS: " << depth_fps << endl;
}
void DualCamera::save(ofstream& file) const {
    if (file.is_open()) {
        file << "Dual Camera Model: " << model << endl;
        file << "Camera: " << camera << endl;
        file << "Resolution: " << resolution << endl;
        file << "FPS: " << fps << endl;
        file << "FOV: " << fov << endl;
        file << "Depth FPS: " << depth_fps << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void Lidar::set(const string& lidar_model, int lidar_channels, int lidar_range, int lidar_power) {
    model = lidar_model;
    channels = lidar_channels;
    range = lidar_range;
    power = lidar_power;
}
void Lidar::print() const {
    cout << "Lidar Model: " << model << endl;
    cout << "Channels: " << channels << endl;
    cout << "Range: " << range << " m" << endl;
    cout << "Power: " << power << " W" << endl;
}
void Lidar::save(ofstream& file) const {
    if (file.is_open()) {
        file << "Lidar Model: " << model << endl;
        file << "Channels: " << channels << endl;
        file << "Range: " << range << " m" << endl;
        file << "Power: " << power << " W" << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void IMU::set(const string& imu_model, const string& imu_manufacturer) {
    model = imu_model;
    manufacturer = imu_manufacturer;
}
void IMU::print() const {
    cout << "IMU Model: " << model << endl;
    cout << "Manufacturer: " << manufacturer << endl;
}
void IMU::save(ofstream& file) const {
    if (file.is_open()) {
        file << "IMU Model: " << model << endl;
        file << "Manufacturer: " << manufacturer << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void Screen::set(double screen_size, const string& screen_model) {
    size = screen_size;
    model = screen_model;
}
void Screen::print() const {
    cout << "Screen Size: " << size << " inches" << endl;
    cout << "Screen Model: " << model << endl;
}
void Screen::save(ofstream& file) const {
    if (file.is_open()) {
        file << "Screen Size: " << size << " inches" << endl;
        file << "Screen Model: " << model << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void Battery::set(const string& battery_params, const string& battery_voltage, const string& battery_charge) {
    params = battery_params;
    voltage = battery_voltage;
    charge = battery_charge;
}
void Battery::print() const {
    cout << "Battery Params: " << params << endl;
    cout << "Battery Voltage: " << voltage << endl;
    cout << "Battery Charge Time: " << charge << endl;
}
void Battery::save(ofstream& file) const {
    if (file.is_open()) {
        file << "Battery Params: " << params << endl;
        file << "Battery Voltage: " << voltage << endl;
        file << "Battery Charge Time: " << charge << endl;
    } else {
        cerr << "Unable to open file for writing." << endl;
    }
}

void SmartCar::set(const string& chassis_id) {
    chassis = Chassis();
    chassis.set(chassis_id);
    agx = AGX();
    agx.set();
    dual_camera = DualCamera();
    dual_camera.set();
    lidar = Lidar();
    lidar.set();
    imu = IMU();
    imu.set();
    screen = Screen();
    screen.set();
    battery = Battery();
    battery.set();
}
void SmartCar::setID(const string& car_id) {
    id = car_id;
}
void SmartCar::print() const {
    cout << "SmartCar ID: " << id << endl;
    chassis.print();
    agx.print();
    dual_camera.print();
    lidar.print();
    imu.print();
    screen.print();
    battery.print();
}
void SmartCar::save(const string& file_path) const {
    ofstream file(file_path, ios::out);
    if (file.is_open()) {
        file << "SmartCar ID: " << id << endl;
        chassis.save(file);
        agx.save(file);
        dual_camera.save(file);
        lidar.save(file);
        imu.save(file);
        screen.save(file);
        battery.save(file);
        file.close();
    } else {
        cerr << "Unable to open file for writing." << endl;
        return;
    }
}
vector<string> SmartCar::get() const {
    return {id, chassis.get()};
}